#include "tdd.h"
#include <string>

TDD::UnitTestBase* TDD::UnitTestBase::test_table = NULL;

class MyDiscriminator : public TDD::Discriminator
{
private:
	int _argc;
	char** _argv;
	int _start;

public:
	MyDiscriminator (int argc, char** argv, int start) : _argc(argc), _argv(argv), _start(start) {}
	virtual bool WantTest(const TDD::UnitTestInfo& uti) const
	{
		if (_argc == _start)
		{
			return true;
		}

		// does uti's char *group and char *testname match any of the args?
		for (int i=_start; i<_argc; i++) 
		{
			char buffer[256+1];
			strncpy(buffer, _argv[i], 256);
			char * tmp = strchr (buffer, ':');

			if (tmp) 
			{
				*tmp++ = '\0';
			}

			if (strcmp(buffer, uti.group))
			{
				continue;
			}

			if (tmp && strcmp (tmp, uti.testname))
			{
				continue;
			}

			return true;
		}

		return false;
	}
};

class MyReporter : public TDD::Reporter
{
private:
	int _failures, _testsRun;
	bool _bVerbose;

public:
	MyReporter(bool bVerbose) : _failures(0), _testsRun(0), _bVerbose(bVerbose) {}
	~MyReporter()
	{
		if (!_testsRun)
		{
			printf("TDD> No tests run!!!\n");
		}
		else
		{
			printf(
				"TDD> %i failure%s out of %i test%s run\n",
				_failures,
				_failures == 1 ? "" : "s",
				_testsRun,
				_testsRun == 1 ? "" : "s");
		}
	}

	void ForEachTestStart(const TDD::UnitTestInfo& uti)
	{
		_testsRun++;
		printf("TDD> Test Running: %s:%s\n",uti.group,uti.testname);
	}

	void ForEachTestEnd(const TDD::UnitTestInfo& uti)
	{
		printf("TDD> Test Completed: %s:%s - %s\n\n", uti.group, uti.testname, (uti.status ? "Succeeded":"Failed"));
	}

	void ForEachFailure(const TDD::TestVerification& tr)
	{
		_failures++;

		if (_bVerbose)
		{
			printf("TDD> %s:%s: Verification failed \"%s\" - file %s(%ld)\n", tr.group, tr.testname, tr.name_string, tr.file_name, tr.line_number);
		}
		else
		{
			printf("TDD> Verification Failure: %s(%ld) : \"%s\"\n", tr.file_name, tr.line_number, tr.name_string);
		}
	}

	void ForEachSuccess(const TDD::TestVerification& tr)
	{
		if (_bVerbose)
		{
			printf("TDD> %s:%s: Verification succeeded \"%s\" - file %s(%ld)\n", tr.group,tr.testname,tr.name_string,tr.file_name,tr.line_number);
		}
	}

	void ForEachMessage(const TDD::TestMessage& tm)
	{
		printf("TDD> Message: %s\n", tm.message_string);
	}

	int GetFailureCount() const { return _failures; }
	int GetTestsRunCount() const { return _testsRun; }
};

class DumpTestDiscriminator : public TDD::Discriminator
{
	virtual bool WantTest(const TDD::UnitTestInfo& uti)
	{
		printf("%s:%s\n", uti.group, uti.testname);
		return false;
	}
};

class DumpTestReporter : public TDD::Reporter
{
	virtual void ForEachFailure(const TDD::TestFailure& tr) {}
};

int __cdecl main(int argc, char** argv)
{
	// test for usage, first:  /? or -?
	if (argc == 2) 
	{
		if ((!strcmp(argv[1], "/?")) ||
			(!strcmp(argv[1], "-?")) )
		{
			TDD::UnitTestBase::RunTests (DumpTestDiscriminator(), DumpTestReporter());
			return 0;
		}
	}
    
	int argstart=1;
	bool bVerbose = false;
	for (int i=1; i<argc; i++)
	{
		if (argv[i][0] == '/')
		{
			argstart=i+1;
			if (toupper(argv[i][1]) == 'V')
			{
				bVerbose = true;
			}
		}
	}

	// run tests that want to run
	MyReporter mf(bVerbose);
	MyDiscriminator md(argc, argv, argstart);
	TDD::UnitTestBase::RunTests (md, mf);

	// report result
	if (mf.GetTestsRunCount() == 0)
	{
		return -1;
	}

	if (mf.GetFailureCount() > 0)
	{
		printf("\nTDD> Test failure summary:\n");
		const TDD::UnitTestBase* p = TDD::UnitTestBase::GetTests();

		while (NULL != p) 
		{
			if (!p->status)
			{
				printf("TDD>\tTest %s:%s failed.\n", p->group, p->testname);
			}

			p = p->GetNext();
		}

		return -1;
	}

	return 0;
}

